/**
 @file ctc_asw_register.c

 @author  Copyright (C) 2020 Centec Networks Inc.  All rights reserved.

 @date 2020-06-15

 @version v2.0

 The file contains all chip APIs
*/

/****************************************************************************
*
* Header Files
*
****************************************************************************/
#include "ctc_asw_common.h"
#include "ctc_asw_port.h"
#include "ctc_asw_register.h"
#include "ctc_asw_parser.h"
#include "ctc_register.h"
#include "asw/include/drv_api.h"
/****************************************************************************
*
* Defines and Macros
*
*****************************************************************************/

/****************************************************************************
*
* Global and Declaration
*
*****************************************************************************/
extern int32
_ctc_asw_init_chip_global_cfg(uint8 lchip);
extern int32
_ctc_asw_chip_gpio_init(uint8 lchip);
extern int32
_ctc_asw_chip_led_init(uint8 lchip);

#define ______INTERNAL______
/**
 @brief Set glb l2mc property
*/
STATIC int32
_ctc_asw_register_set_glb_ipmc_property(uint8 lchip, ctc_global_ipmc_property_t* p_ipmc_property)
{
    uint32  cmd = 0;
    int32   ret = 0;
    uint32  i = 0;
    MacLkupCtrl_m  mac_lkup_ctrl;

    CTC_PTR_VALID_CHECK(p_ipmc_property);

    for (i = 0; i < CTC_ASW_MAX_PORT_NUM_PER_CHIP; i++)
    {
        cmd = DRV_IOR(MacLkupCtrl_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, i, cmd, &mac_lkup_ctrl);
        SetMacLkupCtrl(V,ipmcEnable_f, &mac_lkup_ctrl,(p_ipmc_property->ip_l2mc_mode) ? 1 : 0);
        cmd = DRV_IOW(MacLkupCtrl_t, DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip, i, cmd, &mac_lkup_ctrl);
    }

    return ret;
}

STATIC int32
_ctc_asw_register_set_glb_acl_property(uint8 lchip, ctc_global_acl_property_t* p_acl_prop)
{
    uint32  cmd = 0;
    int32   ret = 0;
    AclGlobalKeyCtrl_m  acl_cfg;

    CTC_PTR_VALID_CHECK(p_acl_prop);
    CTC_MAX_VALUE_CHECK(p_acl_prop->key_ipv6_sa_addr_mode, CTC_GLOBAL_IPV6_ADDR_COMPRESS_MODE_3);
    CTC_MAX_VALUE_CHECK(p_acl_prop->key_ipv6_da_addr_mode, CTC_GLOBAL_IPV6_ADDR_COMPRESS_MODE_3);
    CTC_MAX_VALUE_CHECK(p_acl_prop->mac_ipv6_key_u0_mode, 1);
    CTC_MAX_VALUE_CHECK(p_acl_prop->mac_ipv6_key_u1_mode, 1);
    
    cmd = DRV_IOR(AclGlobalKeyCtrl_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &acl_cfg);
    
    SetAclGlobalKeyCtrl(V, ipv6Sa32Sel_f, &acl_cfg, p_acl_prop->key_ipv6_sa_addr_mode);
    SetAclGlobalKeyCtrl(V, ipv6Da32Sel_f, &acl_cfg, p_acl_prop->key_ipv6_da_addr_mode);
    SetAclGlobalKeyCtrl(V, ipv6Addr1Mode_f, &acl_cfg, p_acl_prop->mac_ipv6_key_u0_mode);
    SetAclGlobalKeyCtrl(V, ipv6Addr2Mode_f, &acl_cfg, p_acl_prop->mac_ipv6_key_u1_mode);
    SetAclGlobalKeyCtrl(V, macSel_f, &acl_cfg, p_acl_prop->l2l3_key_u2_mode);

    cmd = DRV_IOW(AclGlobalKeyCtrl_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &acl_cfg);

    return ret;
}


STATIC int32
_ctc_asw_register_get_glb_ipmc_property(uint8 lchip, ctc_global_ipmc_property_t* p_ipmc_property)
{
    uint32  cmd = 0;
    int32   ret = 0;
    MacLkupCtrl_m  mac_lkup_ctrl;

    cmd = DRV_IOR(MacLkupCtrl_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &mac_lkup_ctrl);
    p_ipmc_property->ip_l2mc_mode = GetMacLkupCtrl(V,ipmcEnable_f, &mac_lkup_ctrl);

    return ret;
}

#define ______INTERNAL_API______
int32
_ctc_asw_register_get_glb_acl_property(uint8 lchip, ctc_global_acl_property_t* p_acl_prop)
{
    uint32  cmd = 0;
    int32   ret = 0;
    AclGlobalKeyCtrl_m  acl_cfg;

    CTC_PTR_VALID_CHECK(p_acl_prop);
    
    cmd = DRV_IOR(AclGlobalKeyCtrl_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &acl_cfg);
    
    p_acl_prop->key_ipv6_sa_addr_mode = GetAclGlobalKeyCtrl(V, ipv6Sa32Sel_f, &acl_cfg);
    p_acl_prop->key_ipv6_da_addr_mode = GetAclGlobalKeyCtrl(V, ipv6Da32Sel_f, &acl_cfg);
    p_acl_prop->mac_ipv6_key_u0_mode = GetAclGlobalKeyCtrl(V, ipv6Addr1Mode_f, &acl_cfg);
    p_acl_prop->mac_ipv6_key_u1_mode = GetAclGlobalKeyCtrl(V, ipv6Addr2Mode_f, &acl_cfg);
    p_acl_prop->l2l3_key_u2_mode = GetAclGlobalKeyCtrl(V, macSel_f, &acl_cfg);

    return ret;
}

int32
_ctc_asw_bitmap_alloc(uint8 lchip, uint32* bitmap_array, uint16 start_idx, uint16 max_idx, uint32* p_idx)
{
    uint32  index = 0;
    for (index=start_idx;index<max_idx;index++)
    {
        if (!CTC_IS_BIT_SET(bitmap_array[index>>5], index%32))
        {
            CTC_BIT_SET(bitmap_array[index>>5],index%32);
            *p_idx = index;
            return CTC_E_NONE;
        }
    }

    return CTC_E_NO_RESOURCE;
}

int32
_ctc_asw_bitmap_free(uint8 lchip, uint32* bitmap_array, uint32 index)
{

    CTC_BIT_UNSET(bitmap_array[index>>5], index%32);

    return CTC_E_NONE;
}

int32
_ctc_asw_bitmap_check_active(uint8 lchip, uint32* bitmap_array, uint32 index)
{
    if (CTC_IS_BIT_SET(bitmap_array[index>>5], index%32))
    {
        return CTC_E_EXIST;
    }

    return CTC_E_NONE;
}

#define ______API______
int32
ctc_asw_global_ctl_set(uint8 lchip, ctc_global_control_type_t type, void* value)
{
    int32 ret = CTC_E_NONE;
    ArlCtrlReg_m    arc_ctrl;
    uint32  cmd = 0;
    CTC_PTR_VALID_CHECK(value);

    CTC_API_LOCK(lchip);
    switch(type)
    {
        case CTC_GLOBAL_IPMC_PROPERTY:
            CTC_ERROR_RETURN_UNLOCK(_ctc_asw_register_set_glb_ipmc_property(lchip, (ctc_global_ipmc_property_t*)value));
            break;
        case CTC_GLOBAL_ACL_PROPERTY:
            CTC_ERROR_RETURN_UNLOCK(_ctc_asw_register_set_glb_acl_property(lchip, (ctc_global_acl_property_t*)value));
            break;
        case CTC_GLOBAL_DISCARD_MCAST_SA_PKT:
        case CTC_GLOBAL_DISCARD_MACSA_0_PKT:
            cmd = DRV_IOR(ArlCtrlReg_t, DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, 0, cmd, &arc_ctrl);
            SetArlCtrlReg(V,sa0OrMcDrop_f,&arc_ctrl,*(uint32*)value);
            cmd = DRV_IOW(ArlCtrlReg_t,DRV_ENTRY_FLAG);
            ret = ret ? ret :DRV_IOCTL(lchip,0,cmd,&arc_ctrl);
            break;
        default:
            ret = CTC_E_INVALID_PARAM;
            break;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_global_ctl_get(uint8 lchip, ctc_global_control_type_t type, void* value)
{
    int32 ret = CTC_E_NONE;
    ArlCtrlReg_m    arc_ctrl;
    uint32  cmd = 0;
    CTC_PTR_VALID_CHECK(value);

    CTC_API_LOCK(lchip);
    switch(type)
    {
        case CTC_GLOBAL_IPMC_PROPERTY:
            CTC_ERROR_RETURN_UNLOCK(_ctc_asw_register_get_glb_ipmc_property(lchip, (ctc_global_ipmc_property_t*)value));
            break;
        case CTC_GLOBAL_ACL_PROPERTY:
            CTC_ERROR_RETURN_UNLOCK(_ctc_asw_register_get_glb_acl_property(lchip, (ctc_global_acl_property_t*)value));
            break;
        case CTC_GLOBAL_CHIP_CAPABILITY:
        {
            uint32* p_capability = (uint32*)value;
            p_capability[CTC_GLOBAL_CAPABILITY_MAX_FID] = 4095;
            p_capability[CTC_GLOBAL_CAPABILITY_VLAN_NUM] = CTC_ASW_MAX_VLAN;
            p_capability[CTC_GLOBAL_CAPABILITY_STP_INSTANCE_NUM] = 32;
            p_capability[CTC_GLOBAL_CAPABILITY_LINKAGG_GROUP_NUM] = 5;
            p_capability[CTC_GLOBAL_CAPABILITY_LINKAGG_MEMBER_NUM] = 8;
        }
            break;
        case CTC_GLOBAL_DISCARD_MCAST_SA_PKT:
        case CTC_GLOBAL_DISCARD_MACSA_0_PKT:
            cmd = DRV_IOR(ArlCtrlReg_t, DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, 0, cmd, &arc_ctrl);
            *(uint32*)value = GetArlCtrlReg(V,sa0OrMcDrop_f,&arc_ctrl);
            break;
        default:
            ret = CTC_E_INVALID_PARAM;
            break;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}


/**
 @brief Initialize the chip module and set the local chip number of the linecard
*/
int32
ctc_asw_register_init(uint8 lchip, void* p_global_cfg)
{
    int32 ret = 0;
    uint32 cmd = 0;
    Stagtpid_m stag_tpid;
    Ctagtpid_m ctag_tpid;
    ChecksumDebug_m chk_sum;

    sal_memset(&ctag_tpid, 0, sizeof(ctag_tpid));
    sal_memset(&stag_tpid, 0, sizeof(stag_tpid));
    sal_memset(&chk_sum, 0, sizeof(chk_sum));

    CTC_ERROR_RETURN(_ctc_asw_chip_led_init(lchip));
    CTC_ERROR_RETURN(_ctc_asw_chip_gpio_init(lchip));
    CTC_ERROR_RETURN(_ctc_asw_init_chip_global_cfg(lchip));

    cmd = DRV_IOR(Stagtpid_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &stag_tpid);
    SetStagtpid(V,tpid0_f,&stag_tpid,0x8100);/*efault use 0x8100*/
    SetStagtpid(V,tpid1_f,&stag_tpid,0x9100);
    SetStagtpid(V,tpid2_f,&stag_tpid,0x88a8);
    SetStagtpid(V,tpid3_f,&stag_tpid,0x88a8);
    cmd = DRV_IOW(Stagtpid_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, 0, cmd, &stag_tpid));
    cmd = DRV_IOR(Ctagtpid_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, 0, cmd, &ctag_tpid));
    SetCtagtpid(V,tpid0_f,&ctag_tpid,0x8100);/*default use 0x8100*/
    SetCtagtpid(V,tpid1_f,&ctag_tpid,0x8100);
    cmd = DRV_IOW(Ctagtpid_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : (DRV_IOCTL(lchip, 0, cmd, &ctag_tpid));

    cmd = DRV_IOW(ChecksumDebug_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip, 0, cmd, &chk_sum);

    return ret;
}

int32
ctc_asw_register_deinit(uint8 lchip)
{
    return CTC_E_NONE;
}

/*parser set/get tpid*/
int32
ctc_asw_parser_set_tpid(uint8 lchip, ctc_parser_l2_tpid_t type, uint16 tpid)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    Stagtpid_m stag_tpid;
    Ctagtpid_m ctag_tpid;

    sal_memset(&ctag_tpid, 0, sizeof(ctag_tpid));
    sal_memset(&stag_tpid, 0, sizeof(stag_tpid));

    CTC_API_LOCK(lchip);
    switch(type)
    {
        case CTC_PARSER_L2_TPID_CVLAN_TPID:
            cmd = DRV_IOR(Ctagtpid_t, DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, 0, cmd, &ctag_tpid);
            SetCtagtpid(V,tpid0_f,&ctag_tpid,tpid);
            SetCtagtpid(V,tpid1_f,&ctag_tpid,tpid);
            cmd = DRV_IOW(Ctagtpid_t, DRV_ENTRY_FLAG);
            ret = ret ? ret : (DRV_IOCTL(lchip, 0, cmd, &ctag_tpid));
            break;
        case CTC_PARSER_L2_TPID_SVLAN_TPID_0:
        case CTC_PARSER_L2_TPID_SVLAN_TPID_1:
        case CTC_PARSER_L2_TPID_SVLAN_TPID_2:
        case CTC_PARSER_L2_TPID_SVLAN_TPID_3:
            cmd = DRV_IOR(Stagtpid_t, DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, 0, cmd, &stag_tpid);
            SetStagtpid(V,tpid0_f- (type-CTC_PARSER_L2_TPID_SVLAN_TPID_0),&stag_tpid,tpid);
            cmd = DRV_IOW(Stagtpid_t, DRV_ENTRY_FLAG);
            ret = ret ? ret : (DRV_IOCTL(lchip, 0, cmd, &stag_tpid));
            break;
        default:
            ret = CTC_E_INVALID_PARAM;
            break;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_parser_get_tpid(uint8 lchip, ctc_parser_l2_tpid_t type, uint16* tpid)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    Stagtpid_m stag_tpid;
    Ctagtpid_m ctag_tpid;

    sal_memset(&ctag_tpid, 0, sizeof(ctag_tpid));
    sal_memset(&stag_tpid, 0, sizeof(stag_tpid));

    CTC_API_LOCK(lchip);
    switch(type)
    {
        case CTC_PARSER_L2_TPID_CVLAN_TPID:
            cmd = DRV_IOR(Ctagtpid_t, DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, 0, cmd, &ctag_tpid);
            *tpid = GetCtagtpid(V,tpid0_f,&ctag_tpid);
            break;
        case CTC_PARSER_L2_TPID_SVLAN_TPID_0:
        case CTC_PARSER_L2_TPID_SVLAN_TPID_1:
        case CTC_PARSER_L2_TPID_SVLAN_TPID_2:
        case CTC_PARSER_L2_TPID_SVLAN_TPID_3:
            cmd = DRV_IOR(Stagtpid_t, DRV_ENTRY_FLAG);
            ret = DRV_IOCTL(lchip, 0, cmd, &stag_tpid);
            *tpid = GetStagtpid(V,tpid0_f- (type-CTC_PARSER_L2_TPID_SVLAN_TPID_0),&stag_tpid);
            break;
        default:
            ret = CTC_E_INVALID_PARAM;
            break;
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}
